package com.google.code.sfa.parse;

import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.BufferedInputStream;

import org.biojava.bio.*;
import org.biojava.bio.seq.Sequence;
import org.biojava.bio.seq.SequenceIterator;
import org.biojava.bio.seq.db.*;
import org.biojava.bio.seq.io.*;
import org.biojava.bio.symbol.*;

public class TraceInfoParser {

    private XMLStreamReader parser;
    private String basename;
    private TraceDatabase traceDB;

    public TraceInfoParser( String basename) throws IOException {
	this.basename = basename;
	String filename = basename + "/traces/TRACEINFO.xml";
	try {
	    XMLInputFactory inputFactory = XMLInputFactory.newInstance();
	    InputStream is = new FileInputStream( filename);
	    parser = inputFactory.createXMLStreamReader( is);
	} catch ( XMLStreamException e) {
	    throw new IOException( e);
	}

    }


    public boolean parse() {
	traceDB = new TraceDatabase();
	try{ 
	    while( parser.hasNext() ) {
		int event = parser.next();
		switch( event) {
		case XMLStreamConstants.START_ELEMENT:
		    if( "trace".equals( parser.getLocalName()) ) {
			Trace t = readTrace();
			traceDB.addTrace( t );
		    }
		    break;
		}
	    }
	    return true;
	} catch( XMLStreamException e) {
	    e.printStackTrace();
	    return false;
	}
    }

    public TraceDatabase getTraceDatabase() {
	return traceDB;
    }

    /*
      start and stop attributes are 1-based inclusive ranges

      clone_id is the same for both ends of the read
      trace_end is the direction of the read (FORWARD OR REVERSE) OR UNKNOWN

     */

    private Trace readTrace() throws XMLStreamException {
	int quality_left = 0, quality_right = 0;
	String name = "", cloneId = "";
	boolean forward = true;
	Sequence seq = null;
	while( parser.hasNext() ) {

	    int event = parser.next();
	    String tag;
	    switch( event) {
	    case XMLStreamConstants.START_ELEMENT:
		tag = parser.getLocalName();
		if( "clip_quality_left".equals( tag ) ) {
		    try {
			quality_left = Integer.parseInt( readText() );
		    } catch( NumberFormatException e) {
		    }
		} else if( "clip_quality_right".equals( tag )) {
		    try {
			quality_right = Integer.parseInt( readText() );
		    } catch( NumberFormatException e) {
		    }
		} else if( "trace_name".equals( tag )) {
		    name = readText();
		} else if( "clone_id".equals( tag )) {
		    cloneId = readText();
		} else if( "trace_end".equals( tag )) {
		    forward = ! "REVERSE".equals( readText() );		    
		} else if( "base_file".equals( tag )) {
		    String filename = this.basename + "/traces/" + readText();
		    seq = readFastaFile( filename);
		}
		break;
	    case XMLStreamConstants.END_ELEMENT:
		tag = parser.getLocalName();
		if( "trace".equals( tag ) ) {
		    if( quality_left != 0 && quality_right != 0 && 
			name != "" && cloneId != "" && seq != null) {
			return new Trace( name, cloneId, seq.subList(quality_left, quality_right), forward);
		    }
		}
		break;
	    }
	}
	return null;
    }

    private String readText() throws XMLStreamException {
	String text = "";
	while( parser.hasNext() ) {

	    int event = parser.next();
	    switch( event) {
	    case XMLStreamConstants.CHARACTERS:
		text += parser.getText();
		break;
	    case XMLStreamConstants.END_ELEMENT:
		return text;
	    }
	}
	return text;
    }

    private Sequence readFastaFile( String filename) {
	try {
	    BufferedInputStream is = new BufferedInputStream( new FileInputStream( filename));
	    Alphabet alpha = AlphabetManager.alphabetForName( "DNA");
	    SequenceDB db = SeqIOTools.readFasta( is, alpha);
	    SequenceIterator iter = db.sequenceIterator();
	    if( iter.hasNext() ) {
		return iter.nextSequence();
	    } else {
		return null;
	    }
	} catch( Exception e) {
	    e.printStackTrace();
	    return null;
	}
    }

}